﻿using Quartz;
using SimulationCenter.Jobs;
using SimulationCenter.Tasks;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace SimulationCenter.Schedulers
{
    /// <summary>
    /// 调度器管理器
    /// </summary>
    public class ScScheduleManager : IDisposable
    {
        private readonly ISchedulerFactory _factory;

        public ScScheduleManager(ISchedulerFactory factory)
        {
            _factory = factory;
        }

        /// <summary>
        /// 任务恢复调度器
        /// </summary>
        /// <returns></returns>
        public async Task RecoveryTasksSchedule()
        {
            var schedule = await _factory.GetScheduler();

            await schedule.Start();

            var job = JobBuilder.Create<ScStartUpJob>()
                .WithIdentity("startup_job", "startup")
                .Build();

            var trigger = TriggerBuilder.Create()
                .WithIdentity("startup_trigger", "startup")
                .StartNow()
                .Build();

            await schedule.ScheduleJob(job, trigger);
        }

        /// <summary>
        /// 创建主任务计划
        /// </summary>
        /// <param name="scTask"></param>
        public async Task AddScTaskSchedule(ScTask scTask)
        {
            var schedule = await _factory.GetScheduler();

            await schedule.Start();

            var job = JobBuilder.Create<ScJob>()
                .WithIdentity($"{nameof(ScTask)}_jobs_{scTask.Id}", $"{nameof(ScTask)}_jobs")
                .WithDescription(scTask.Description)
                .UsingJobData(ScJob.ScTaskId, scTask.Id)
                .Build();

            var triggerBuilder = TriggerBuilder.Create()
                .WithIdentity($"{nameof(ScTask)}_triggers_{scTask.Id}", $"{nameof(ScTask)}_triggers")
                .StartNow();

            triggerBuilder = scTask.LoopMode == ScLoopMode.Once
                ? triggerBuilder
                : triggerBuilder.WithCronSchedule(scTask.Cron, s => s.InTimeZone(TimeZoneInfo.Local));

            var trigger = triggerBuilder
                .Build();

            await schedule.ScheduleJob(job, trigger);
        }

        /// <summary>
        /// 添加子任务计划
        /// </summary>
        /// <param name="scTaskId"></param>
        /// <param name="device"></param>
        /// <returns></returns>
        public async Task AddDeviceTaskSchedule(int scTaskId, string device)
        {
            var schedule = await _factory.GetScheduler();

            await schedule.Start();

            var job = JobBuilder.Create<ScDeviceJob>()
                .WithIdentity($"{nameof(ScDeviceTask)}_jobs_{scTaskId}_{device}", $"{nameof(ScDeviceTask)}_jobs")
                .UsingJobData(ScDeviceJob.ScTaskId, scTaskId)
                .UsingJobData(ScDeviceJob.Device, device)
                .Build();

            var trigger = TriggerBuilder.Create()
                .WithIdentity($"{nameof(ScDeviceTask)}_triggers_{scTaskId}_{device}",
                    $"{nameof(ScDeviceTask)}_triggers")
                .StartNow()
                .Build();

            await schedule.ScheduleJob(job, trigger);
        }

        /// <summary>
        /// 关闭所有调度器
        /// </summary>
        public void Dispose()
        {
            _factory.GetAllSchedulers()
                .GetAwaiter()
                .GetResult()
                .ToList()
                .ForEach(s =>
                {
                    if (s.IsStarted && !s.IsShutdown)
                    {
                        s.Shutdown().GetAwaiter().GetResult();
                    }
                });
        }
        
        #region privates 

        #endregion
    }
}
